package com.ztjava.pay.controller;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.Element;

import com.jfinal.aop.Before;
import com.jfinal.aop.Duang;
import com.jfinal.kit.Ret;
import com.jfinal.plugin.redis.Cache;
import com.jfinal.plugin.redis.Redis;
import com.xiaoleilu.hutool.date.DateUtil;
import com.ztjava.core.Constant;
import com.ztjava.core.annotation.ControllerClass;
import com.ztjava.core.base.BaseController;
import com.ztjava.core.client.member.MobileClient;
import com.ztjava.core.tool.ViewTool;
import com.ztjava.core.utiliy.RequestUtil;
import com.ztjava.ext.auth.annotation.UserController;
import com.ztjava.ext.auth.annotation.UserMethod;
import com.ztjava.ext.auth.bean.AuthSession;
import com.ztjava.pay.model.PayOrder;
import com.ztjava.pay.service.PayService;
import com.ztjava.pay.tool.WeixinPayTool;
import com.ztjava.pay.validator.PayValidator;


@ControllerClass(path="/pay/weixin",client=MobileClient.class)
@UserController(portal=Constant.P_MEMBER)
public class PayWeixinMobileController extends BaseController {
	private static Logger logger = Logger.getLogger(PayWeixinMobileController.class);
	private static final String PAY_WEIXIN_APIKEY = "PAY_WEIXIN_APIKEY";
	
	private static PayService payService = Duang.duang(PayService.class);
	
	@UserMethod
	@Before(PayValidator.class)
	public void getPayParams(){
		Cache cache = Redis.use();
		if(cache.exists(Constant.R_PRE+"PAY:REPAIR")){
			renderError("支付系统维护中，请稍后再试！");
			return;
		}
		AuthSession authSession = getAttr(Constant.AUTHSESSION);
		String openid = cache.hget(Constant.R_PRE+"AUTH:THIRD:WEIXIN", authSession.getId());
		if(openid==null||openid.equals("")){
			renderError("请在微信端重新打开！");
			return;
		}
		PayOrder payOrder = getAttr("payOrder");
		payOrder.set("pay_channel","WEIXIN-PUBLIC").set("pay_time",DateUtil.date().toTimestamp()).update();
		renderRet(WeixinPayTool.getParams(payOrder, RequestUtil.getDomain(getRequest()),
				RequestUtil.getIp(getRequest()), getAttrForStr(Constant.PRE_PATH), openid));
	}
	
	@UserMethod
	public void doPay(){
		String num = getPara("num","");
		PayOrder payOrder = payService.getOrderByNum(num);
		if(payOrder==null){
			setAttr(Constant.MESSAGE, "订单不存在！");
			render("doPay.html");
			return;
		}
		if(payOrder.getStr("status").equals("CANCEL")){
			setAttr(Constant.MESSAGE, "已取消支付！");
			render("doPay.html");
			return;
		}
		if(payOrder.getStr("status").equals("PAID")){
			setAttr(Constant.MESSAGE, "请勿重复支付！");
			render("doPay.html");
			return;
		}
		if(payOrder.getTimestamp("create_time").getTime()<DateUtil.offsetMinute(new Date(), -30).getTime()){
			setAttr(Constant.MESSAGE, "订单信息已过期！");
			render("doPay.html");
			return;
		}
		Cache cache = Redis.use();
		AuthSession authSession = getAttr(Constant.AUTHSESSION);
		String openid = cache.hget(Constant.R_PRE+"AUTH:THIRD:WEIXIN", authSession.getId());
		if(openid==null||openid.equals("")){
			setAttr(Constant.MESSAGE, "请在微信端重新打开！");
			render("doPay.html");
			return;
		}
		setAttr("payOrder", payOrder);
		keepPara();
		Ret ret = WeixinPayTool.getParams(payOrder, RequestUtil.getDomain(getRequest()),
				RequestUtil.getIp(getRequest()), getAttrForStr(Constant.PRE_PATH), openid);
		if(ret.getStr(Constant.RESULT).equals(Constant.SUCCESS)){
			payOrder.set("pay_channel","WEIXIN-PUBLIC")
			.set("pay_time",DateUtil.date().toTimestamp()).update();
			setAttr("payParams",ret.getStr("params"));
		}else {
			setAttr(Constant.MESSAGE, ret.getStr(Constant.MESSAGE));
		}
		render("doPay.html");
	}
	
	private static final Object lock = new Object();
	//支付成功通知
	public void notifyResult(){
		
		Element root = null;
		String xmlData = RequestUtil.readData(getRequest());
		try{
			Document document = WeixinPayTool.safeParseXml(xmlData);
			if(document==null){
	        	logger.warn("document为null");
				renderError(500);
				return;
			}
			root = document.getRootElement();
		}catch (Exception e) {
			e.printStackTrace();
			renderNull();
			return;
		}
		SortedMap<Object,Object> success = new TreeMap<Object,Object>();
		success.put("return_code", "SUCCESS");
		success.put("return_msg", "OK");
		Element out_trade_no  = root.element("out_trade_no");
		Cache cache = Redis.use();
		synchronized (lock) {
			if(cache.exists(Constant.R_PRE+"PAY:INFO:NUM:"+out_trade_no.getText())){
				logger.warn(out_trade_no.getText()+"重复通知支付成功");
				renderText(WeixinPayTool.createXml(success));
				return;
			}
			cache.setex(Constant.R_PRE+"PAY:INFO:NUM:"+out_trade_no.getText(), 3600, true);
		}

		PayOrder payOrder = payService.getOrderByNum(out_trade_no.getText());
		if(payOrder==null||!payOrder.getStr("status").equals("READY")){
			renderText(WeixinPayTool.createXml(success));
			return;
		}

		Element result_code = root.element("result_code");
		if(result_code.getText().equals("FAIL")) {
			payOrder.set("pay_msg", root.element("err_code").getText()+":"+root.element("err_code_des").getText())
			.set("pay_result", Constant.ERROR)
			.update();
			renderText(WeixinPayTool.createXml(success));
			return;
		}
		Element total_fee = root.element("total_fee");
		int order_total_fee = payOrder.getBigDecimal("money").multiply(new BigDecimal("100")).intValue();
		if(order_total_fee!=Integer.parseInt(total_fee.getText())){
			payOrder.set("pay_msg", "付款金额为"+Integer.parseInt(total_fee.getText())+"，与订单金额"+order_total_fee+"不符！")
					.set("pay_result", Constant.ERROR).update();
			renderText(WeixinPayTool.createXml(success));
			return;
		}
		
		SortedMap<Object,Object> parameters = new TreeMap<Object,Object>();
		List<Element> elementList = root.elements();
		for(int i=0;i<elementList.size();i++){
			parameters.put(elementList.get(i).getName(), elementList.get(i).getText());
		}
		String sign = root.element("sign").getText();
		if(!sign.equals(WeixinPayTool.createSign(parameters,ViewTool.param(PAY_WEIXIN_APIKEY)))){
			payOrder.set("pay_result", Constant.ERROR).set("pay_msg", "签名检测失败！").update();
			renderText(WeixinPayTool.createXml(success));
			return;
		}
		//用于微信端通知组成url
		payOrder.put("come_domain", RequestUtil.getDomain(getRequest()));
		payService.paySuccess(payOrder,root.element("transaction_id").getText());
		
		renderText(WeixinPayTool.createXml(success));
		
	}
	
}
